package com.yichi.service;

import android.util.Log;

import com.jeremyliao.liveeventbus.LiveEventBus;
import com.licheedev.modbus4android.ModbusRespException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.yichi.device_bean.BmsParam;
import com.yichi.device_bean.BmsStatus;
import com.yichi.device_bean.PcbDataInfo;
import com.yichi.device_bean.PcbStatusInfo;
import com.yichi.device_bean.PlcInfo;
import com.yichi.global.AppConfig;
import com.yichi.global.EventDef;
import com.yichi.manager.ModbusRtuManager;
import com.yichi.util.JsonUtil;
import com.yichi.util.Utils;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * PCB（控制板串口）通信服务
 */
public class PcbService {

    private static final String TAG = "PcbService";

    private ModbusRtuManager modbusRtuManager;
    private boolean loopQueryFlag = true;//定时查询状态

    /**
     * 单例模式
     */
    public static PcbService inst = new PcbService();

    private PcbService() {
    }

    public void init() {
        modbusRtuManager = new ModbusRtuManager();
        modbusRtuManager.initPcbRTU();
    }

    public void startQueryPcbTask() {
        Executors.newSingleThreadExecutor().execute(new queryPcbTask());
    }

    /**
     * 定时查询控制板状态
     */
    public class queryPcbTask implements Runnable {
        @Override
        public void run() {
            while (loopQueryFlag) {
                Integer startIndex = DeviceService.inst.rechargeStoreStartIndex;
                Integer storeCount = DeviceService.inst.rechargeStoreCount;

                PcbDataInfo pcbDataInfo = queryDataInfo(startIndex, storeCount);
                if (pcbDataInfo != null) {
                    LiveEventBus.get(EventDef.EVENT_PCB_DATA_QUERY_TASK, PcbDataInfo.class).post(pcbDataInfo);
                }

                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                PcbStatusInfo pcbStatusInfo = queryStatusInfo(startIndex, storeCount);
                if (pcbStatusInfo != null) {
                    LiveEventBus.get(EventDef.EVENT_PCB_STATUS_QUERY_TASK, PcbStatusInfo.class).post(pcbStatusInfo);
                }
                try {
                    Thread.sleep(8000);//8秒
                } catch (InterruptedException e) {
                    Log.e(TAG, e.getMessage(), e);
                }
            }
        }
    }

    /**
     * 批量查询充电仓状态信息
     *
     * @param chargingStoreStartIndex 充电仓起始地址
     * @return
     */
    public PcbStatusInfo queryStatusInfo(Integer chargingStoreStartIndex, Integer chargingStoreStartCount) {
        try {
            int slaveId = AppConfig.PCB_MODBUS_SLAVE_ID;
            int offset = 1;

            //计算寄存器数量
            int num1 = chargingStoreStartCount - 1;
            int num2 = (int) Math.ceil(num1 / 2);//向上取整
            int count = num2 + 1;

//        ArrayList<Integer> integers = modbusRtuManager.readMultipleRegisters(slaveId, offset, count);
//        ArrayList<Short> shorts = Utils.integerList2ShortList(integers);
//        byte[] bytes = Utils.shortList2ByteArray(shorts);

            byte[] bytes = modbusRtuManager.readMultipleRegistersBytesSync(slaveId, offset, count);
            if (bytes == null || bytes.length <= 0) {
                return null;
            }
            String[] strings = Utils.byteArray2BinaryStringArray(bytes);

            PcbStatusInfo pcbStatusInfo = new PcbStatusInfo();
            pcbStatusInfo.setBmsStatusMap(new HashMap<>());
            //柜体状态
            String str1 = Utils.reverseString(strings[0]);
            pcbStatusInfo.setDeviceWD(Utils.getDigitAtPosition(str1, 0));
            pcbStatusInfo.setDeviceSW(Utils.getDigitAtPosition(str1, 1));
            pcbStatusInfo.setDeviceYW(Utils.getDigitAtPosition(str1, 2));
            //充电仓状态
            for (int i = 1; i < strings.length; i++) {
                if (i > chargingStoreStartCount) break;

                BmsStatus bmsStatus = new BmsStatus();

                String str2 = Utils.reverseString(strings[i]);
                bmsStatus.setCdzt(Utils.getDigitAtPosition(str2, 0));
                bmsStatus.setDxycgd(Utils.getDigitAtPosition(str2, 1));
                bmsStatus.setCdgl(Utils.getDigitAtPosition(str2, 2));
                bmsStatus.setCdgwbh(Utils.getDigitAtPosition(str2, 3));
                bmsStatus.setCddwbh(Utils.getDigitAtPosition(str2, 4));
                bmsStatus.setMosCDSH(Utils.getDigitAtPosition(str2, 5));
                bmsStatus.setMosFDSH(Utils.getDigitAtPosition(str2, 6));

                pcbStatusInfo.getBmsStatusMap().put(chargingStoreStartIndex.toString(), bmsStatus);
                chargingStoreStartIndex++;
            }
            Log.i(TAG, "BMS状态：" + JsonUtil.toJSONString(pcbStatusInfo));

            return pcbStatusInfo;
        } catch (Exception e) {
            Log.e(TAG, e.getMessage(), e);
            return null;
        }
    }

    /**
     * 批量查询充电仓状态信息
     *
     * @param chargingStoreStartIndex 充电仓起始地址
     * @return
     */
    public PcbStatusInfo queryStatusInfoEx(Integer chargingStoreStartIndex, Integer chargingStoreStartCount) throws Exception {
        int slaveId = AppConfig.PCB_MODBUS_SLAVE_ID;
        int offset = 1;

        //计算寄存器数量
        int num1 = chargingStoreStartCount - 1;
        int num2 = (int) Math.ceil(num1 / 2);//向上取整
        int count = num2 + 1;

//        ArrayList<Integer> integers = modbusRtuManager.readMultipleRegisters(slaveId, offset, count);
//        ArrayList<Short> shorts = Utils.integerList2ShortList(integers);
//        byte[] bytes = Utils.shortList2ByteArray(shorts);

        byte[] bytes = modbusRtuManager.readMultipleRegistersBytesSync(slaveId, offset, count);
        if (bytes == null || bytes.length <= 0) {
            throw new Exception("没读取到控制板数据");
        }
        String[] strings = Utils.byteArray2BinaryStringArray(bytes);

        PcbStatusInfo pcbStatusInfo = new PcbStatusInfo();
        pcbStatusInfo.setBmsStatusMap(new HashMap<>());
        //柜体状态
        String str1 = Utils.reverseString(strings[0]);
        pcbStatusInfo.setDeviceWD(Utils.getDigitAtPosition(str1, 0));
        pcbStatusInfo.setDeviceSW(Utils.getDigitAtPosition(str1, 1));
        pcbStatusInfo.setDeviceYW(Utils.getDigitAtPosition(str1, 2));
        //充电仓状态
        for (int i = 1; i < strings.length; i++) {
            if (i > chargingStoreStartCount) break;

            BmsStatus bmsStatus = new BmsStatus();

            String str2 = Utils.reverseString(strings[i]);
            bmsStatus.setCdzt(Utils.getDigitAtPosition(str2, 0));
            bmsStatus.setDxycgd(Utils.getDigitAtPosition(str2, 1));
            bmsStatus.setCdgl(Utils.getDigitAtPosition(str2, 2));
            bmsStatus.setCdgwbh(Utils.getDigitAtPosition(str2, 3));
            bmsStatus.setCddwbh(Utils.getDigitAtPosition(str2, 4));
            bmsStatus.setMosCDSH(Utils.getDigitAtPosition(str2, 5));
            bmsStatus.setMosFDSH(Utils.getDigitAtPosition(str2, 6));

            pcbStatusInfo.getBmsStatusMap().put(chargingStoreStartIndex.toString(), bmsStatus);
            chargingStoreStartIndex++;
        }

        return pcbStatusInfo;
    }

    public PcbDataInfo queryDataInfo(Integer chargingStoreStartIndex, Integer chargingStoreStartCount) {
        try {
            int slaveId = AppConfig.PCB_MODBUS_SLAVE_ID;
            int offset = 1001;
            int count = 66;

            PcbDataInfo pcbDataInfo = new PcbDataInfo();
            pcbDataInfo.setBmsParamMap(new HashMap<>());

            byte[] gtBytes = modbusRtuManager.readMultipleRegistersBytesSync(slaveId, offset, count);

//        byte[] gtBytes = {
//                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32,
//                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32,
//                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32,
//                0x00, 0x00, 0x00
//        };

            //解析柜体
            pcbDataInfo.setDeviceHJWD(Utils.byte2Integer(gtBytes[0]) - 40);
            pcbDataInfo.setDeviceGDDY(Utils.byte2Integer(gtBytes[1]));
            byte[] tmpBytes1 = {gtBytes[2], gtBytes[3]};
            int tmpInt1 = Utils.twoBytesToInt(tmpBytes1);
            pcbDataInfo.setDeviceGDDL((float) (tmpInt1 * 0.01));
            byte[] tmpBytes2 = {gtBytes[4], gtBytes[5]};
            int tmpInt2 = Utils.twoBytesToInt(tmpBytes2);
            pcbDataInfo.setDeviceYGGL((float) (tmpInt2 * 0.001));
            byte[] tmpBytes3 = {gtBytes[6], gtBytes[7], gtBytes[8], gtBytes[9]};
            int tmpInt3 = Utils.fourBytesToInt(tmpBytes3);
            pcbDataInfo.setDeviceZDN((double) (tmpInt3 * 0.01));
            Log.i(TAG, "柜体信息：" + JsonUtil.toJSONString(pcbDataInfo));

            //解析电池
            for (int i = 0; i < chargingStoreStartCount; i++) {
                byte[] dcBytes = new byte[40];
                System.arraycopy(gtBytes, i * 40 + 12, dcBytes, 0, 40);

                BmsParam bmsParam = new BmsParam();

                //解析电池编号
                byte[] bytes2 = new byte[26];
                System.arraycopy(dcBytes, 0, bytes2, 0, 26);
                String batteryNo = new String(bytes2, StandardCharsets.US_ASCII);
                batteryNo = batteryNo.replace("\u0000", "");
                bmsParam.setBatteryNo(batteryNo);

                byte[] bytes3 = new byte[2];
                System.arraycopy(dcBytes, 26, bytes3, 0, 2);
                int int3 = Utils.twoBytesToInt(bytes3);
                bmsParam.setTotalVoltage((float) (int3 * 0.01));

                byte[] bytes4 = new byte[1];
                System.arraycopy(dcBytes, 28, bytes4, 0, 1);
                int int4 = Utils.oneByteToInt(bytes4[0]);
                bmsParam.setSoc(int4);

                byte[] bytes5 = new byte[1];
                System.arraycopy(dcBytes, 29, bytes5, 0, 1);
                int int5 = Utils.oneByteToInt(bytes5[0]);
                bmsParam.setSoh(int5);

                byte[] bytes6 = new byte[2];
                System.arraycopy(dcBytes, 30, bytes6, 0, 2);
                int int6 = Utils.twoBytesToInt(bytes6);
                bmsParam.setCellHighVoltage((float) (int6 * 0.001));

                byte[] bytes7 = new byte[2];
                System.arraycopy(dcBytes, 32, bytes7, 0, 2);
                int int7 = Utils.twoBytesToInt(bytes7);
                bmsParam.setCellLowVoltage((float) (int7 * 0.001));

                byte[] bytes8 = new byte[2];
                System.arraycopy(dcBytes, 34, bytes8, 0, 2);
                int int8 = Utils.twoBytesToInt(bytes8);
                bmsParam.setRechargeCurrent((float) (int8 * 0.01));

                byte[] bytes9 = new byte[1];
                System.arraycopy(dcBytes, 36, bytes9, 0, 1);
                int int9 = Utils.oneByteToInt(bytes9[0]);
                bmsParam.setEnvTemp(int9 - 40);

                byte[] bytes10 = new byte[1];
                System.arraycopy(dcBytes, 37, bytes10, 0, 1);
                int int10 = Utils.oneByteToInt(bytes10[0]);
                bmsParam.setCellTemp(int10 - 40);

//                Log.i(TAG, "bms数据：" + i + ":" + JsonUtil.toJSONString(bmsParam));
                pcbDataInfo.getBmsParamMap().put(chargingStoreStartIndex, bmsParam);

                chargingStoreStartIndex++;
            }

            return pcbDataInfo;

        } catch (Exception e) {
            Log.e(TAG, e.getMessage(), e);
        }
        return null;
    }

    /**
     * 批量查询充电仓数据信息
     * 有问题，弃用
     *
     * @return
     */
    public PcbDataInfo queryDataInfoEx(Integer chargingStoreStartIndex, Integer chargingStoreStartCount) {
        try {
            int slaveId = AppConfig.PCB_MODBUS_SLAVE_ID;
            int offset = 0;

            PcbDataInfo pcbDataInfo = new PcbDataInfo();
            pcbDataInfo.setBmsParamMap(new HashMap<>());

            //先读柜体，第6个保留
            int startOffset = 1001, count = 6;
//            byte[] gtBytes = modbusRtuManager.readMultipleRegistersBytesSync(slaveId, startOffset, count);
            byte[] gtBytes = {
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32,
                    0x00, 0x00, 0x00
            };

            pcbDataInfo.setDeviceHJWD(Utils.byte2Integer(gtBytes[0]) - 40);
            pcbDataInfo.setDeviceGDDY(Utils.byte2Integer(gtBytes[1]));
            byte[] tmpBytes1 = {gtBytes[2], gtBytes[3]};
            int tmpInt1 = Utils.twoBytesToInt(tmpBytes1);
            pcbDataInfo.setDeviceGDDL((float) (tmpInt1 * 0.01));
            byte[] tmpBytes2 = {gtBytes[4], gtBytes[5]};
            int tmpInt2 = Utils.twoBytesToInt(tmpBytes2);
            pcbDataInfo.setDeviceYGGL((float) (tmpInt2 * 0.001));
            byte[] tmpBytes3 = {gtBytes[6], gtBytes[7], gtBytes[8], gtBytes[9]};
            int tmpInt3 = Utils.fourBytesToInt(tmpBytes3);
            pcbDataInfo.setDeviceZDN((double) (tmpInt3 * 0.01));
            Log.i(TAG, "柜体信息：" + JsonUtil.toJSONString(pcbDataInfo));

            //计算循环次数
            int loopNum = (int) Math.ceil((float) chargingStoreStartCount / 6);
            int modNum = chargingStoreStartCount % 6;//取模
            startOffset = 1007;
            int dataLen = 20;//1个充电仓20个寄存器。40个字节
            Log.i(TAG, "循环总次数：" + loopNum);
            for (int i = 0; i < loopNum; i++) {
                Log.i(TAG, "循环第" + i + "次");
                //计算寄存器数量
                if (modNum > 0) {
                    if (i == loopNum - 1) {
                        //最后一个
                        count = modNum * dataLen;
                    } else {
                        count = 6 * dataLen;
                    }
                } else {
                    count = 6 * dataLen;
                }
                //计算偏移地址
                if (i == 0) {
                    offset = startOffset;
                } else {
                    offset = startOffset + ((i + 1) * dataLen);
                }
//            ArrayList<Integer> integers = modbusRtuManager.readMultipleRegisters(slaveId, offset, count);
//            ArrayList<Short> shorts = Utils.integerList2ShortList(integers);
//            Short[] secondArray = Utils.shortList2ShortArray(shorts);

                byte[] bytes = modbusRtuManager.readMultipleRegistersBytesSync(slaveId, offset, count);
                //解析充电仓数据
                int byteLen = dataLen * 2;
                int storeNum = bytes.length / byteLen;
                for (int x = 0; x < storeNum; x++) {
                    BmsParam bmsParam = new BmsParam();

                    //解析电池编号
                    byte[] bytes2 = new byte[26];
                    System.arraycopy(bytes, x * byteLen, bytes2, 0, 26);
                    String batteryNo = new String(bytes2, StandardCharsets.US_ASCII);
                    batteryNo = batteryNo.replace("\u0000", "");
                    bmsParam.setBatteryNo(batteryNo);

                    byte[] bytes3 = new byte[2];
                    System.arraycopy(bytes, x * byteLen + 13, bytes3, 0, 2);
                    int int3 = Utils.twoBytesToInt(bytes3);
                    bmsParam.setTotalVoltage((float) (int3 * 0.01));

                    byte[] bytes4 = new byte[1];
                    System.arraycopy(bytes, x * byteLen + 15, bytes4, 0, 1);
                    int int4 = Utils.oneByteToInt(bytes4[0]);
                    bmsParam.setSoc(int4);

                    byte[] bytes5 = new byte[1];
                    System.arraycopy(bytes, x * byteLen + 16, bytes5, 0, 1);
                    int int5 = Utils.oneByteToInt(bytes5[0]);
                    bmsParam.setSoh(int5);

                    byte[] bytes6 = new byte[2];
                    System.arraycopy(bytes, x * byteLen + 17, bytes6, 0, 2);
                    int int6 = Utils.twoBytesToInt(bytes6);
                    bmsParam.setCellHighVoltage((float) (int6 * 0.001));

                    byte[] bytes7 = new byte[2];
                    System.arraycopy(bytes, x * byteLen + 19, bytes7, 0, 2);
                    int int7 = Utils.twoBytesToInt(bytes7);
                    bmsParam.setCellLowVoltage((float) (int7 * 0.001));

                    byte[] bytes8 = new byte[2];
                    System.arraycopy(bytes, x * byteLen + 21, bytes8, 0, 2);
                    int int8 = Utils.twoBytesToInt(bytes8);
                    bmsParam.setRechargeCurrent((float) (int8 * 0.01));

                    byte[] bytes9 = new byte[1];
                    System.arraycopy(bytes, x * byteLen + 23, bytes9, 0, 1);
                    int int9 = Utils.oneByteToInt(bytes9[0]);
                    bmsParam.setEnvTemp(int9 - 40);

                    byte[] bytes10 = new byte[1];
                    System.arraycopy(bytes, x * byteLen + 24, bytes10, 0, 1);
                    int int10 = Utils.oneByteToInt(bytes10[0]);
                    bmsParam.setCellTemp(int10 - 40);

                    Log.i(TAG, "bms数据：" + x + ":" + JsonUtil.toJSONString(bmsParam));
                    pcbDataInfo.getBmsParamMap().put(chargingStoreStartIndex, bmsParam);
                    chargingStoreStartIndex++;
                }

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            return pcbDataInfo;
        } catch (Exception e) {
            Log.e(TAG, e.getMessage(), e);
            return null;
        }
    }

    /**
     * 操作充电仓充电
     * 编号为0控制所有
     */
    public void powerOn(Integer storeNo) {
        int slaveId = AppConfig.PCB_MODBUS_SLAVE_ID;
        int offset = 4001;

        byte[] bytes = new byte[2];
        bytes[0] = Utils.intToOneByte(storeNo);
        bytes[1] = 0x01;

        short[] shorts = Utils.byteArray2ShortArray(bytes);
        modbusRtuManager.writeRegistersCmd(slaveId, offset, shorts);
    }

    /**
     * 操作充电仓断电
     * 编号为0控制所有
     */
    public void powerOff(Integer storeNo) {
        int slaveId = AppConfig.PCB_MODBUS_SLAVE_ID;
        int offset = 4001;

        byte[] bytes = new byte[2];
        bytes[0] = Utils.intToOneByte(storeNo);
        bytes[1] = 0x00;

        short[] shorts = Utils.byteArray2ShortArray(bytes);
        modbusRtuManager.writeRegistersCmd(slaveId, offset, shorts);
    }

    public void testCmd() {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    //测试查询状态
//                    PcbStatusInfo pcbStatusInfo = queryStatusInfo(16, 6);
//                    Log.i(TAG, "pcb测试查询状态结果:" + JsonUtil.toJSONString(pcbStatusInfo));
//                    测试查询数据
                    PcbDataInfo pcbDataInfo = queryDataInfo(16, 7);
                    Log.i(TAG, "pcb测试查询数据结果:" + JsonUtil.toJSONString(pcbDataInfo));
//                    ArrayList<Integer> integers = modbusRtuManager.readMultipleRegisters(20, 1001, 126);
//                    ArrayList<Short> shorts = Utils.integerList2ShortList(integers);
//                    Log.i(TAG, "pcb测试查询数据结果:" + JsonUtil.toJSONString(shorts));

//                    ArrayList<Integer> integers = modbusRtuManager.readMultipleRegisters(20, 1001, 6);
//                    Log.i(TAG, "pcb测试查询数据结果:" + JsonUtil.toJSONString(integers));
                } catch (Exception e) {
                    Log.e(TAG, "pcb query failed", e);
                }

                try {
                    Thread.sleep(1000); // Sleep for 100ms (adjust as needed)
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start(); // Start the background thread
    }

}
